home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / pascal / bbskt30a.zip / MTASK20.ZIP / MTASK.PAS < prev    next >
Pascal/Delphi Source File  |  1990-03-15  |  13KB  |  515 lines

  1. UNIT mtask;
  2.  
  3.  
  4. {MTASK 2.0, a simple multi-tasker unit for Turbo Pascal 5.
  5.  
  6. Written in November, 1988, and donated to the public domain by:
  7.  
  8.    Wayne E. Conrad
  9.    2627 North 51st Ave, #219
  10.    Phoenix, AZ  85035
  11.    BBS: (602) 484-9356, 300/1200/2400, 24 hours/day
  12.  
  13. This unit provides Turbo Pascal 5 with what I call "request driven"
  14. multi-tasking.  Switching from the current task to another task is done
  15. whenever the current task requests a task switch by calling procedure
  16. "switch_task."  No interrupt driven context switching is done, because
  17. it's a hassle.
  18.  
  19. See accompanying files for documentation and examples.}
  20.  
  21.  
  22. {$F+}  {Most procedures in this unit must be FAR}
  23.  
  24.  
  25. INTERFACE
  26.  
  27.  
  28. {Result codes.  0 is "no error"}
  29.  
  30. CONST
  31.   heap_full       = 1;   {Unable to allocate heap for the task's stack}
  32.   too_many_tasks  = 2;   {Maximum number of tasks are already running}
  33.   invalid_task_id = 3;   {There is no task with that ID number}
  34.  
  35.  
  36. {This is the procedure type for a task.  The parent task can pass any
  37. type of variable to  the child task.}
  38.  
  39. TYPE
  40.   task_proc = PROCEDURE (VAR param);
  41.  
  42.  
  43. {See the IMPLEMENTATION section for descriptions of these procedures and
  44. functions.}
  45.  
  46. PROCEDURE create_task
  47.   (
  48.   task      : task_proc;
  49.   VAR param ;
  50.   stack_size: Word;
  51.   VAR id    : Word;
  52.   VAR result: Word
  53.   );
  54. PROCEDURE terminate_task (id: Word; VAR result: Word);
  55. PROCEDURE switch_task;
  56. FUNCTION current_task_id: Word;
  57. FUNCTION number_of_tasks: Word;
  58.  
  59.  
  60. IMPLEMENTATION
  61.  
  62.  
  63. {The maximum number of tasks.  Modify to suit your needs.}
  64.  
  65. CONST
  66.   max_tasks = 16;
  67.  
  68.  
  69. {This record contains all the information about a task, as follows:
  70.  
  71.   stack_ptr:   Saved stack segment (ss) and stack pointer (sp) registers
  72.  
  73.   stack_org:   If the stack is stored on the heap, this is the address of
  74.                the beginning of the block of memory allocated for the stack.
  75.  
  76.   stack_bytes: Size of stack on the heap, or 0 if the stack is not on the
  77.                heap.  If the stack is not on the heap, then this field is 0.
  78.  
  79.   bp:          Saved value of base pointer (BP) register.
  80.  
  81.   id:          The id number of the task
  82.  
  83. Note that DS (Data Segment register) is not stored.  We can get away with
  84. this by assuming that all tasks will use the same data segment.}
  85.  
  86. TYPE
  87.   task_rec =
  88.     RECORD
  89.     stack_ptr  : Pointer;
  90.     stack_org  : Pointer;
  91.     stack_bytes: Word;
  92.     bp         : Word;
  93.     id         : Word;
  94.     END;
  95.  
  96.  
  97. {The number of tasks in the system}
  98.  
  99. VAR
  100.   ntasks: Word;
  101.  
  102.  
  103. {Information for each task.}
  104.  
  105. VAR
  106.   task_info: ARRAY [1..max_tasks] OF task_rec;
  107.  
  108.  
  109. {The last task ID assigned.  If we haven't rolled the id's over, then
  110. this allows us to assign task ID's without checking to see what id's have
  111. been assigned.}
  112.  
  113. VAR
  114.   last_id    : Word;
  115.   id_rollover: Boolean;
  116.  
  117.  
  118. {This is the task number of the currently executing task}
  119.  
  120. VAR
  121.   current_task: Word;
  122.  
  123.  
  124. {This is the record type of the initial contents of the stack when a task
  125. is created.  When the task is first switched to, it will be from within
  126. the switch_task, terminate_task, or terminate_current_task procedure.  At
  127. the end of switch_task, BP will be popped, then a far return will be
  128. done.  The far return will transfer to the beginning of task.  The task
  129. can access the parameter "task_param," which is a pointer to whatever
  130. data structure that the creator of this task wanted to pass to the new
  131. task.  When the task finally exits, a far return to "end_task" will be
  132. done.  The exception is the main task, which ends the program completely
  133. if it exits.}
  134.  
  135. TYPE
  136.   initial_stack_rec_ptr = ^initial_stack_rec;
  137.   initial_stack_rec =
  138.     RECORD
  139.     bp        : Word;
  140.     task_addr : task_proc;
  141.     end_task  : Pointer;
  142.     task_param: Pointer;
  143.     END;
  144.  
  145.  
  146. {Given a task ID, return the task number, or 0 if there is no task with
  147. that ID.}
  148.  
  149. FUNCTION find_task (target_id: Word): Word;
  150. VAR
  151.   n: Word;
  152. BEGIN
  153.   n := 1;
  154.   WHILE (n <= ntasks) AND (task_info [n].id <> target_id) DO
  155.     Inc (n);
  156.   IF (n > ntasks) THEN
  157.     n := 0;
  158.   find_task := n
  159. END;
  160.  
  161.  
  162. {Remove a task's information from the task info array, and decrement the
  163. number of tasks.}
  164.  
  165. PROCEDURE delete_task_info (task_num: Word);
  166. VAR
  167.   i: Word;
  168. BEGIN
  169.   FOR i := task_num TO ntasks - 1 DO
  170.     task_info [i] := task_info [i + 1];
  171.   Dec (ntasks)
  172. END;
  173.  
  174.  
  175. {Terminate the current task.  If the current task is the only task, then
  176. the program is halted.  If the current task's stack was allocated from
  177. the heap, it is freed.}
  178.  
  179. PROCEDURE terminate_current_task;
  180.  
  181.  
  182. {These are defined as constants to force them into the data segment.
  183. They can't be local, because local variables are stored on the stack and
  184. we're going to switch to a different task (and therefore to a different
  185. stack) before we're done with these variables.}
  186.  
  187. CONST
  188.   old_stack_org  : Pointer = NIL;
  189.   old_stack_bytes: Word = 0;
  190.  
  191.  
  192. VAR
  193.   task_num : Word;
  194.   new_stack: Pointer;
  195.   new_bp   : Word;
  196.  
  197.  
  198. BEGIN {terminate_current_task}
  199.  
  200.   {If we're the last task left, then exit to DOS}
  201.  
  202.   IF ntasks <= 1 THEN
  203.     Halt;
  204.  
  205.   {Remember where the task's stack is so that we can free it up if it's
  206.   on the heap.  We can't free it now, because we're still using it!}
  207.  
  208.   WITH task_info [current_task] DO
  209.     BEGIN
  210.     old_stack_org   := stack_org;
  211.     old_stack_bytes := stack_bytes
  212.     END;
  213.  
  214.   {Remove the task's information from the task info array}
  215.  
  216.   delete_task_info (current_task);
  217.   IF current_task > ntasks THEN
  218.     current_task := 1;
  219.  
  220.   {Switch to the next task.  The stack_ptr and bp are transfered into
  221.   local variables because it's much easier to access simple variables in
  222.   INLINE code than it is to access array variables.}
  223.  
  224.   WITH task_info [current_task] DO
  225.     BEGIN
  226.     new_stack := stack_ptr;
  227.     new_bp    := bp
  228.     END;
  229.   INLINE
  230.     (
  231.     $8b/$86/>new_stack+0/     {MOV  AX,[BP].NEW_STACK+0}
  232.     $8b/$96/>new_stack+2/     {MOV  DX,[BP].NEW_STACK+2}
  233.     $8b/$ae/>new_bp/          {MOV  BP,[BP].NEW_BP}
  234.     $fa/                      {CLI}
  235.     $8e/$d2/                  {MOV  SS,DX}
  236.     $8b/$e0/                  {MOV  SP,AX}
  237.     $fb                       {STI}
  238.     );
  239.  
  240.   {If the task we just got rid of had its heap on the stack, then release
  241.   that memory back to the free pool.}
  242.  
  243.   IF old_stack_bytes > 0 THEN
  244.     FreeMem (old_stack_org, old_stack_bytes)
  245.  
  246. END;
  247.  
  248.  
  249. {Terminate a task.  If task_id is 0, then the current task is deleted.
  250. Possible result codes are:
  251.  
  252.   0                   No error
  253.   invalid_task_id     There is no task with that ID number}
  254.  
  255. PROCEDURE terminate_task (id: Word; VAR result: Word);
  256.  
  257.  
  258.   {Delete a task.  Do not use to delete the current task!}
  259.  
  260.   PROCEDURE delete_task (task_num: Word);
  261.   BEGIN
  262.     WITH task_info [task_num] DO
  263.       IF stack_bytes > 0 THEN
  264.         FreeMem (stack_org, stack_bytes);
  265.     delete_task_info (task_num);
  266.     IF current_task > task_num THEN
  267.       Dec (current_task)
  268.   END;
  269.  
  270.  
  271. VAR
  272.   task_num: Word;
  273.  
  274. BEGIN {terminate_task}
  275.   result := 0;
  276.   IF id = 0 THEN
  277.     terminate_current_task
  278.   ELSE
  279.     BEGIN
  280.     task_num := find_task (id);
  281.     IF task_num = 0 THEN
  282.       result := invalid_task_id
  283.     ELSE
  284.       IF task_num = current_task THEN
  285.         terminate_current_task
  286.       ELSE
  287.         delete_task (task_num)
  288.     END
  289. END;
  290.  
  291.  
  292. {Create a new task and pass parameter "param" to it.  Stack space for the
  293. task is allocated from the heap, and the stack is initialized so that
  294. procedure "new_task" will be executed with parameter "param".  Result
  295. codes are:
  296.  
  297.   0                  No error occured
  298.   heap_full          Unable to allocate heap for the task's stack
  299.   too_many_tasks     Maximum number of tasks are already running
  300.  
  301. If an error occurs, then id is not set.  Otherwise, id is the task id of
  302. the newly created task.}
  303.  
  304. PROCEDURE create_task
  305.   (
  306.   task      : task_proc;
  307.   VAR param ;
  308.   stack_size: Word;
  309.   VAR id    : Word;
  310.   VAR result: Word
  311.   );
  312.  
  313.  
  314. {This is the task number of the task we're creating}
  315.  
  316. VAR
  317.   task_num: Word;
  318.  
  319.  
  320.   {Allocate stack space for the task.